package com.yeyaomai.dksns.flowis.quartz;

import java.text.ParseException;
import java.util.Date;
import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.data.mongodb.core.mapreduce.GroupByResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import com.yeyaomai.dksns.flowis.dao.DetailDao;
import com.yeyaomai.dksns.flowis.dao.MongoDBBasicDao;
import com.yeyaomai.dksns.flowis.dao.VisitAreaDao;
import com.yeyaomai.dksns.flowis.domain.VisitArea;
import com.yeyaomai.dksns.flowis.domain.flowisdetail.FlowisStatDetailDTO;
import com.yeyaomai.dksns.flowis.util.CollectionNames;
import com.yeyaomai.dksns.flowis.util.Globals;

public class VisitAreaExecutor extends MongoDBBasicDao<VisitArea> {

	@Resource
	private DetailDao detailDao;
	
	@Resource
	private VisitAreaDao visitAreaDao;
	
	final Logger logger = Logger.getLogger("quartz");
	
	public void saveVisitArea() throws ParseException
	{
		Date date = new Date();
		Date dates = new Date(date.getTime() - 1 * 3600 * 1000);
		String formDate = Globals.FORMAT_TYPE_A.format(dates);
		String toDate = Globals.FORMAT_TYPE_A.format(date);
		if(formDate.equals(toDate))
		{
			toDate = Globals.FORMAT_TYPE_A.format(new Date(Globals.FORMAT_TYPE_A.parse(toDate).getTime()+1 * 24 * 3600 * 1000));
		}
		visitAreaDao.delVisitAreaByDate(formDate);
		GroupByResults<FlowisStatDetailDTO> result = this.getVisitCountByTime(
				formDate, toDate);
		for (FlowisStatDetailDTO engine : result) {
			
			VisitArea visitArea = new VisitArea();
			visitArea.setReferDate(Globals.FORMAT_TYPE_A
					.parse(Globals.FORMAT_TYPE_A.format(dates)));
			if(null != engine.getAccess_city())
			{
				if(engine.getAccess_city().equals(""))
				{
					visitArea.setProvince("其它");
					visitArea.setCity("其它");
				}
				else{
					visitArea.setProvince(this.getProvinceByCity(engine.getAccess_city()));
					visitArea.setCity(engine.getAccess_city());
				}
			}
			else{
				visitArea.setProvince("其它");
				visitArea.setCity("其它");
			}
			visitArea.setVisitCount(engine.getVisitCount());
			Integer uniqueCount = this.getUVByTime(formDate, toDate,
					engine.getAccess_city());
			visitArea.setUniqueHost(uniqueCount);
			Integer ip = this.getIpByTime(formDate, toDate, engine.getAccess_city());
			visitArea.setIp(ip);
			Integer newuniqueHost = this.getNewUVByTime(formDate, toDate,
					engine.getAccess_city());
			visitArea.setNewUniqueHost(newuniqueHost);
			visitArea.setAvgStopTime(this.getAvgStopTime(formDate, toDate, engine.getAccess_city()));
			logger.info(date+"running saveVisit 城市："+engine.getAccess_city()+"ip数"+ip+"PV数"+engine.getVisitCount()+"独立访客:"+uniqueCount+"新独立访客:"+newuniqueHost);
			visitAreaDao.addVisitArea(visitArea);
		}
		
		logger.info("#############################地域分布定时任务执行添加完毕######################");
	}
	
	/**
	 * 按地区统计访问次数
	 */
	private GroupByResults<FlowisStatDetailDTO> getVisitCountByTime(
			String fromTrendDay, String toTrendDay) {

		String mapFunction = "{ visitCount: 0}";
		String reduceFunction = "function(doc, prev) {prev.visitCount+=1}";
		Criteria criteria = Criteria.where("access_date").gte(fromTrendDay).lt(toTrendDay);
		GroupByResults<FlowisStatDetailDTO> result = detailDao
				.group(criteria, CollectionNames.ACCESS_CITY, mapFunction, reduceFunction, FlowisStatDetailDTO.class);
		return result;
	}

	/**
	 * 定时任务处理UV
	 */
	private int getUVByTime(String formDate, String toDate, String accessCity) {
		String mapFunction = "{ visitCount: 0}";
		String reduceFunction = "function(doc, prev) {prev.visitCount+=1}";
		Criteria criteria = Criteria.where("access_date").gte(formDate).lt(toDate).and("access_city").is(accessCity);
		int uvcount = detailDao.group(criteria, CollectionNames.COOKIEID, mapFunction, reduceFunction, FlowisStatDetailDTO.class).getKeys();
		return uvcount;
	}

	/**
	 * 定时任务处理IP
	 */
	private int getIpByTime(String formDate, String toDate, String accessCity) {
		String mapFunction = "{ip: 0}";
		String reduceFunction = "function(doc, prev) {prev.ip+=1}";
		Criteria criteria = Criteria.where("access_date").gte(formDate).lt(toDate).and("access_city").is(accessCity);
		int ipcount = detailDao.group(criteria, CollectionNames.IP, mapFunction, reduceFunction, FlowisStatDetailDTO.class).getKeys();
		return ipcount;
	}

	/**
	 * 定时任务处理newuv
	 */
	private int getNewUVByTime(String formDate, String toDate, String accessCity) {
		int newuvcount = 0;
		String mapFunction = "{cookieId: 0}";
		String reduceFunction = "function(doc, prev) {prev.cookieId+=1}";
		Criteria criteria = Criteria.where("access_date").gte(formDate).lt(toDate).and("access_city").is(accessCity).and("visitCount").is(1);
		newuvcount = detailDao.group(criteria, CollectionNames.COOKIEID, mapFunction, reduceFunction, FlowisStatDetailDTO.class).getKeys();
		return newuvcount;
	}
	
	private String getProvinceByCity(String city)
	{
		if(!city.equals(""))
		{
			FlowisStatDetailDTO flow = new FlowisStatDetailDTO();
			Query query = new Query(Criteria.where("access_city").is(city));
			flow = detailDao.findOne(query);
			return flow.getAccess_province();
		}
		else
		{
			return "其它";
		}
		
	}
	
	/**
	 * 获取平均停留时间
	 * @param formDate开始时间
	 * @param toDate结束时间
	 * @param accessCity城市
	 * @return
	 */
	private Long getAvgStopTime(String formDate, String toDate, String accessCity)
	{
		String mapFunction = "{ visitCount: 0}";
		String reduceFunction = "function(doc, prev) {prev.visitCount+=1}";
		Criteria criteria = Criteria.where("access_date").gte(formDate).lt(toDate).and("access_city").is(accessCity);
		GroupByResults<FlowisStatDetailDTO> result = detailDao
				.group(criteria, CollectionNames.STOPTIME, mapFunction, reduceFunction, FlowisStatDetailDTO.class);
		Long count = 0L;
		for (FlowisStatDetailDTO engine : result)
		{
			if(engine.getStoptime()> 0 )
			{
				count += engine.getStoptime()*engine.getVisitCount();
			}
		}
		return count;
	}
}
